using System;
using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;
using System.Diagnostics;
using System.Reflection;
using Microsoft.Win32;

namespace CriticalSystems.Instrumentation
{
    [RunInstaller(true)]
    public partial class SystemInformationInstaller : Installer
    {
        private readonly Assembly callingAssembly;
        private readonly IRegistryKey hklmSoftwareRegKey;
        private readonly SystemDeploymentParameters deploymentParameters;
        private readonly bool baseInstall = true;
        private InstallContext installContext;

        public SystemInformationInstaller()
        {
            InitializeComponent();
            hklmSoftwareRegKey = new RegistryKeyWrapper(Registry.LocalMachine.OpenSubKey("Software", true));
            callingAssembly = Assembly.GetCallingAssembly();
            deploymentParameters = new SystemDeploymentParameters(callingAssembly);
            var eventLogInstaller = GetEventLogInstaller(deploymentParameters.SystemInformation);
            Installers.Add(eventLogInstaller);
        }

        internal SystemInformationInstaller(InstallContext context, IRegistryKey hklmSoftwareRegKey)
        {
            installContext = context;
            this.hklmSoftwareRegKey = hklmSoftwareRegKey;
            callingAssembly = Assembly.GetCallingAssembly();
            deploymentParameters = new SystemDeploymentParameters(callingAssembly);
            baseInstall = false;
        }

        public override void Install(IDictionary stateSaver)
        {
            if (baseInstall)
            {
                installContext = Context;
                base.Install(stateSaver);
            }
            deploymentParameters.ParseParameters(installContext.Parameters);
            SystemDeploymentParameters.SaveState(stateSaver, installContext.Parameters);

            InstallDiscoveryRegistrySettings(deploymentParameters.SystemInformation);
        }

        public override void Uninstall(IDictionary savedState)
        {
            if (baseInstall)
            {
                installContext = Context;
                base.Uninstall(savedState);
            }
            deploymentParameters.ParseParameters(savedState);
            UninstallDiscoveryRegistrySettings(deploymentParameters.SystemInformation);
        }

        private EventLogInstaller GetEventLogInstaller(SystemInformation systemInformation)
        {
            var eventLogInstaller = new EventLogInstaller {Source = systemInformation.System};

            // Set the event log that the source writes entries to.
            var eventLog = systemInformation.EventLog;
            if (!string.IsNullOrEmpty(eventLog))
            {
                eventLogInstaller.Log = eventLog;
            }

            eventLogInstaller.CategoryResourceFile = callingAssembly.Location;
            eventLogInstaller.CategoryCount = systemInformation.Subsystems.Count;
            eventLogInstaller.MessageResourceFile = callingAssembly.Location;
            return eventLogInstaller;
        }

        private void InstallDiscoveryRegistrySettings(SystemInformation systemInformation)
        {
            var systemKey = hklmSoftwareRegKey.CreateSubKey(systemInformation.System);
            var systemInstanceKey = systemKey.CreateSubKey(systemInformation.Instance);
            foreach (var subsystem in systemInformation.Subsystems)
            {
                var subsystemKey = systemInstanceKey.CreateSubKey(subsystem.Subsystem);
                foreach (var instance in subsystem.Instances)
                {
                    subsystemKey.CreateSubKey(instance);
                }
            }
        }

        private void UninstallDiscoveryRegistrySettings(SystemInformation systemInformation)
        {
            //throw new NotImplementedException(); TODO: uninstall registry instances and delete parents if none left.
        }
    }
}